﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace PDI
{
    public class Processador
    {
        Imagem imgRetorno = new Imagem(new Bitmap(200, 200));


        public Imagem ProcessarImagem(Imagem img1, Imagem img2, EnumTipoProcesso tipoProcesso)
        {
            imgRetorno = new Imagem(new Bitmap(200, 200));

            ImagemProcesso imgProcesso = aplicarOperacao(img1, img2, tipoProcesso);

            for (int x = 0; x < 199; x++)
            {
                for (int y = 0; y < 199; y++)
                {
                    imgRetorno.setRGB(
                        x, y, imgProcesso.imgR[y, x], imgProcesso.imgG[y, x], imgProcesso.imgB[y, x]);
                }

            }

            return imgRetorno;
        }

        private ImagemProcesso aplicarOperacao(Imagem img1, Imagem img2, EnumTipoProcesso tipoProcesso)
        {
            ImagemProcesso imgProcesso = new ImagemProcesso(200, 200);

            for (int x = 0; x < 199; x++)
            {
                int valorR, valorG, valorB;

                valorR = valorG = valorB = 0;

                for (int y = 0; y < 199; y++)
                {
                    switch (tipoProcesso)
                    {
                        case EnumTipoProcesso.Truncar_Adicao:
                        case EnumTipoProcesso.Normalizar_Adicao:

                            valorR = img1.getR(x, y) + img2.getR(x, y);
                            valorG = img1.getG(x, y) + img2.getG(x, y);
                            valorB = img1.getB(x, y) + img2.getB(x, y);
                            break;

                        case EnumTipoProcesso.Normalizar_Subtracao:
                        case EnumTipoProcesso.Truncar_Subtracao:

                            valorR = img1.getR(x, y) - img2.getR(x, y);
                            valorG = img1.getG(x, y) - img2.getG(x, y);
                            valorB = img1.getB(x, y) - img2.getB(x, y);

                            break;

                        case EnumTipoProcesso.Normalizar_Multiplicacao:
                        case EnumTipoProcesso.Truncar_Multiplicacao:

                            valorR = img1.getR(x, y) * img2.getR(x, y);
                            valorG = img1.getG(x, y) * img2.getG(x, y);
                            valorB = img1.getB(x, y) * img2.getB(x, y);

                            break;

                        case EnumTipoProcesso.Truncar_Divisao:
                        case EnumTipoProcesso.Normalizar_Divisao:

                            valorR = img2.getR(x, y) == 0? 0 : img1.getR(x, y) / img2.getR(x, y);
                            valorG = img2.getG(x, y) == 0 ? 0 : img1.getG(x, y) / img2.getG(x, y);
                            valorB = img2.getB(x, y) == 0 ? 0 : img1.getB(x, y) / img2.getB(x, y);

                            break;
                    }

                    imgProcesso.imgR[y, x] = valorR;
                    imgProcesso.imgG[y, x] = valorG;
                    imgProcesso.imgB[y, x] = valorB;

                }
            }

            imgProcesso = tratarProcesso(imgProcesso);

            if (tipoProcesso.ToString().Contains("Normalizar"))
            {
                imgProcesso = Normalizar(imgProcesso);
            }

            return imgProcesso;
        }

        private ImagemProcesso tratarProcesso(ImagemProcesso imgProcesso)
        {
            for (int x = 0; x < 199; x++)
            {
                for (int y = 0; y < 199; y++)
                {
                    imgProcesso.imgR[y, x] =
                        imgProcesso.imgR[y, x] > 255 ? 255 : imgProcesso.imgR[y, x];

                    imgProcesso.imgG[y, x] =
                        imgProcesso.imgG[y, x] > 255 ? 255 : imgProcesso.imgG[y, x];

                    imgProcesso.imgB[y, x] =
                        imgProcesso.imgB[y, x] > 255 ? 255 : imgProcesso.imgB[y, x];

                    imgProcesso.imgR[y, x] =
                        imgProcesso.imgR[y, x] < 0 ? 0 : imgProcesso.imgR[y, x];

                    imgProcesso.imgG[y, x] =
                        imgProcesso.imgG[y, x] < 0 ? 0 : imgProcesso.imgG[y, x];

                    imgProcesso.imgB[y, x] =
                        imgProcesso.imgB[y, x] < 0 ? 0 : imgProcesso.imgB[y, x];

                }
            }
            return imgProcesso;
        }

        private ImagemProcesso Normalizar(ImagemProcesso imgProcesso)
        {
            int MaiorR = pixelMaior(imgProcesso.imgR);
            int MaiorG = pixelMaior(imgProcesso.imgG);
            int MaiorB = pixelMaior(imgProcesso.imgB);

            int MenorR = pixelMenor(imgProcesso.imgR);
            int MenorG = pixelMenor(imgProcesso.imgG);
            int MenorB = pixelMenor(imgProcesso.imgB);

            double fatorNormalizacaoR = MaiorR - MenorR;
            double fatorNormalizacaoG = MaiorG - MenorG;
            double fatorNormalizacaoB = MaiorB - MenorB;

            for (int x = 0; x < 199; x++)
            {
                for (int y = 0; y < 199; y++)
                {
                    imgProcesso.imgR[y, x] = Convert.ToInt32(
                        ((imgProcesso.imgR[y, x] - MenorR) * 255) / (fatorNormalizacaoR));

                    imgProcesso.imgG[y, x] = Convert.ToInt32(
                        ((imgProcesso.imgG[y, x] - MenorG) * 255) / (fatorNormalizacaoG));

                    imgProcesso.imgB[y, x] = Convert.ToInt32(
                        ((imgProcesso.imgB[y, x] - MenorB) * 255) / (fatorNormalizacaoB));
                }
            }

            return imgProcesso;
        }

        private int pixelMaior(int[,] matriz)
        {
            int resultado = int.MinValue;
            for (int x = 0; x < 199; x++)
            {
                for (int y = 0; y < 199; y++)
                {
                    if (matriz[y, x] > resultado)
                    {
                        resultado = matriz[y, x];
                    }
                }
            }
            return resultado;
        }

        private int pixelMenor(int[,] matriz)
        {
            int resultado = int.MaxValue;

            for (int x = 0; x < 199; x++)
            {
                for (int y = 0; y < 199; y++)
                {
                    if (matriz[y, x] < resultado)
                    {
                        resultado = matriz[y, x];
                    }
                }
            }
            return resultado;
        }

        public Imagem converterGrayScaleBT709(Imagem imagem)
        {
            Imagem imagemRetorno = new Imagem(new Bitmap(imagem.getBitmap().Width, imagem.getBitmap().Height));

            double valorQuebradoR = 0.0;
            double valorQuebradoG = 0.0;
            double valorQuebradoB = 0.0;

            int valorCinza = 0;

            for (int linha = 0; linha < imagemRetorno.getBitmap().Height; linha++)
            {
                for (int coluna = 0; coluna < imagemRetorno.getBitmap().Width; coluna++)
                {
                    valorQuebradoR = Convert.ToDouble(imagem.getR(coluna, linha)) * 0.2125;
                    valorQuebradoG = Convert.ToDouble(imagem.getG(coluna, linha)) * 0.7154;
                    valorQuebradoB = Convert.ToDouble(imagem.getB(coluna, linha)) * 0.0721;

                    valorCinza = Convert.ToInt32( Math.Truncate(valorQuebradoR + valorQuebradoG + valorQuebradoB / 3));

                    imagemRetorno.setRGB(coluna, linha, valorCinza, valorCinza, valorCinza);
                }
            }

            return imagemRetorno;
        }

        
    }

}
/*
 * Normalização
 * (VAtual - min) * (255) (max - min)
 * 
 * */
